﻿using System.Diagnostics.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Text;

namespace DimensionsHelper.Common.Contracts.Metadata;

/// <summary>
///     元数据值区间的重叠情况。
/// </summary>
public enum MetadataRangeOverlapType
{
    /// <summary>
    ///     两个区间完全相同。
    /// </summary>
    Equal,

    /// <summary>
    ///     检查的区间完全覆盖当前区间。
    /// </summary>
    Cover,

    /// <summary>
    ///     检查的区间是当前区间的子集。
    /// </summary>
    Include,

    /// <summary>
    ///     检查的区间在当前区间左侧并且有交集。
    /// </summary>
    LeftIntersection,

    /// <summary>
    ///     检查的区间在当前区间的右侧并且有交集。
    /// </summary>
    RightIntersection,

    /// <summary>
    ///     检查区间是当前区间的左邻域。
    /// </summary>
    LeftNeighbourhood,

    /// <summary>
    ///     检查区间是当前区间的右邻域。
    /// </summary>
    RightNeighbourhood,

    /// <summary>
    ///     两个区间没有交集并且在当前区间左边。
    /// </summary>
    LeftNoIntersection,

    /// <summary>
    ///     两个区间没有交集并且在当前区间右边。
    /// </summary>
    RightNoIntersection
}


/// <summary>
///     区间范围值类型
/// </summary>
public enum MetadataRangeValueType
{
    Long = 3,
    Integer = 5,
    Date = 7,
    String = 8,
    Boolean = 11
}


/// <summary>
///     区间的上限或下限
/// </summary>
public enum MetadataRangeBoundaryType
{
    Lower,
    Upper
}


/// <summary>
///     字段值范围
/// </summary>
public class MetadataValueRange(IField owner, object? lowerBound, object? upperBound, object? step = null)
    : IComparable<MetadataValueRange>
{
    /// <summary>
    ///     值区间表达式所在的字段。
    /// </summary>
    public IField Owner { get; } = owner;

    /// <summary>
    ///     上限值
    /// </summary>
    public object? UpperBound { get; private set; } = upperBound;

    /// <summary>
    ///     下限值
    /// </summary>
    public object? LowerBound { get; private set; } = lowerBound;


    /// <summary>
    ///     区间取值的间隔值。
    /// </summary>
    public object? Step { get; set; } = step;


    /// <summary>
    ///     区间值类型
    /// </summary>
    public MetadataRangeValueType ValueType { get; } = (lowerBound ?? upperBound) switch
    {
        string _ => MetadataRangeValueType.String,
        bool _ => MetadataRangeValueType.Boolean,
        long _ => MetadataRangeValueType.Long,
        int _ or null => MetadataRangeValueType.Integer,
        DateTime _ => MetadataRangeValueType.Date,
        _ => throw new NotSupportedException()
    };

    public int CompareTo(MetadataValueRange? other)
    {
        if (other == null)
        {
            return 1;
        }

        return CheckOverlap(other) switch
        {
            MetadataRangeOverlapType.Equal => 0,
            MetadataRangeOverlapType.Cover or MetadataRangeOverlapType.RightIntersection
                or MetadataRangeOverlapType.RightNeighbourhood => 1,
            MetadataRangeOverlapType.Include or MetadataRangeOverlapType.LeftIntersection
                or MetadataRangeOverlapType.LeftNeighbourhood or MetadataRangeOverlapType.LeftNoIntersection => -1,
            _ => 1
        };
    }

    private string GetObjectValue(object? value)
    {
        if (value == null)
        {
            return string.Empty;
        }

        return ValueType switch
        {
            MetadataRangeValueType.Long or MetadataRangeValueType.Integer => ((int)value).ToString(),
            MetadataRangeValueType.Date => $"\"{(DateTime)value}\"",
            MetadataRangeValueType.String => $"\"{(string)value}\"",
            MetadataRangeValueType.Boolean => ((bool)value).ToString(),
            _ => string.Empty
        };
    }

    /// <summary>
    ///     获取上限字符串
    /// </summary>
    /// <returns></returns>
    public string GetUpperBound()
    {
        return GetObjectValue(UpperBound);
    }

    /// <summary>
    ///     获取下限字符串
    /// </summary>
    /// <returns></returns>
    public string GetLowerBound()
    {
        return GetObjectValue(LowerBound);
    }

    /// <summary>
    ///     获取区间表达式， [下限]..[上限]
    /// </summary>
    /// <returns></returns>
    public string GetExpression()
    {
        // 当区间处于循环变量的循环层时
        // 1. 对于 step 不是 0，需要将区间展开成具体值。
        // 2. [.. Upper] 是有效的，[.. Upper Step number] 是无效的，Step不是null或0时，必须同时指定上限和下限。
        if (Owner is IArray arr && arr.IteratorType != IteratorTypes.Categorical &&
            Step is int iStep && iStep != 0)
        {
            if (UpperBound == null || LowerBound == null)
            {
                throw new Exception("指定了'Step'时，上限和下限都不可忽略。");
            }

            int iUpper = (int)UpperBound;
            int iLower = (int)LowerBound;

            // Upper > Lower 时，如果 Step < 0 ，是无效的。
            // Upper < Lower 时，如果 Step > 0 ，是无效的。
            if (iUpper > iLower && iStep < 0 || iUpper < iLower && iStep > 0)
            {
                throw new Exception("区间展开失败：'Step'值无效。");
            }

            if (iUpper == iLower)
            {
                return iUpper.ToString();
            }

            var builder = new StringBuilder();

            for (int i = iLower; i <= iUpper; i += iStep)
            {
                if (builder.Length > 0)
                {
                    builder.Append(", ");
                }

                builder.Append(i);
            }

            return builder.ToString();
        }

        return $"{GetLowerBound()}..{GetUpperBound()}{(Step == null ? "" : " step " + GetObjectValue(Step))}";
    }


    /// <summary>
    ///     比较两个值的大小，使用系统默认对比方法。
    /// </summary>
    /// <param name="val1">第一个值</param>
    /// <param name="val2">第二个值</param>
    /// <param name="valueType">值类型</param>
    /// <returns><paramref name="val1" />-<paramref name="val2" />的值</returns>
    private static int CompareValue(object val1, object val2, MetadataRangeValueType valueType)
    {
        return valueType switch
        {
            MetadataRangeValueType.Integer or MetadataRangeValueType.Boolean => Comparer<int>.Default.Compare(
                (int)val1, (int)val2),
            MetadataRangeValueType.Long => Comparer<long>.Default.Compare((long)val1, (long)val2),
            MetadataRangeValueType.Date => DateTime.Compare((DateTime)val1, (DateTime)val2),
            MetadataRangeValueType.String => string.Compare((string)val1, (string)val2, StringComparison.Ordinal),
            _ => Comparer<object>.Default.Compare(val1, val2)
        };
    }


    /// <summary>
    ///     比较给定值和当前区间的关系。
    /// </summary>
    /// <param name="value">给定值</param>
    /// <returns>给定值和当前区间的差值</returns>
    /// <remarks>
    ///     <list>
    ///         <item>
    ///             <term>小于0</term>
    ///             <description>给定值小于当前区间的区间下限。</description>
    ///         </item>
    ///         <item>
    ///             <term>等于0</term>
    ///             <description>给定值在当前区间内，当前区间是闭区间。</description>
    ///         </item>
    ///         <item>
    ///             <term>大于0</term>
    ///             <description>给定值大于当前区间的区间上限。</description>
    ///         </item>
    ///     </list>
    /// </remarks>
    public int CompareValue(object value)
    {
        int comp;

        // [LowerBound .. [UpperBound]]
        if (LowerBound != null)
        {
            comp = CompareValue(value, LowerBound, ValueType);

            if (comp < 0)
            {
                return comp;
            }

            if (UpperBound == null)
            {
                return 0;
            }

            comp = CompareValue(value, UpperBound, ValueType);
            return comp > 0 ? comp : 0;
        }

        // [ .. UpperBound]
        if (UpperBound == null)
        {
            return 0;
        }

        comp = CompareValue(value, UpperBound, ValueType);
        return comp > 0 ? comp : 0;
    }


    /// <summary>
    ///     扩展当前值范围的上限或下限。
    /// </summary>
    /// <param name="value">给定上限或下限</param>
    /// <remarks>
    ///     依据已有的<see cref="UpperBound" />、<see cref="LowerBound" />和<paramref name="value" />参数值的对比结果更新范围。
    ///     <list type="number">
    ///         <item>
    ///             如果<see cref="LowerBound" /><![CDATA[<=]]><paramref name="value" /><![CDATA[<=]]><see cref="UpperBound" />
    ///             ，不做操作。
    ///         </item>
    ///         <item>
    ///             如果<see cref="LowerBound" />!=null 并且 <paramref name="value" /><![CDATA[<=]]><see cref="LowerBound" />，更新
    ///             <see cref="LowerBound" />为<paramref name="value" />
    ///         </item>
    ///         <item>
    ///             如果<see cref="UpperBound" />!=null 并且 <paramref name="value" /><![CDATA[>=]]><see cref="UpperBound" />，更新
    ///             <see cref="UpperBound" />为<paramref name="value" />
    ///         </item>
    ///     </list>
    /// </remarks>
    public void Expand(object value)
    {
        if (LowerBound == null && UpperBound == null)
        {
            return;
        }

        // [Lower .. [Upper]]
        if (LowerBound != null)
        {
            // value小于Lower时，扩展Lower（下限）。
            if (CompareValue(value, LowerBound, ValueType) < 0)
            {
                LowerBound = value;
            }
            // [Lower .. Upper]
            // value大于Upper，扩展Upper（上限）。
            else if (UpperBound != null && CompareValue(value, UpperBound, ValueType) > 0)
            {
                UpperBound = value;
            }

            return;
        }

        // [.. Upper]
        if (UpperBound != null && CompareValue(value, UpperBound, ValueType) > 0)
        {
            UpperBound = value;
        }
    }


    /// <summary>
    ///     指定扩展上限或下限
    /// </summary>
    /// <param name="boundaryType">指定上限或下限</param>
    /// <param name="value">扩展边界值，当此值是null时，</param>
    public void Expand(MetadataRangeBoundaryType boundaryType, object? value)
    {
        if (boundaryType == MetadataRangeBoundaryType.Lower)
        {
            if (value == null || LowerBound == null)
            {
                LowerBound = null;
            }
            else if (CompareValue(value, LowerBound, ValueType) < 0)
            {
                LowerBound = value;
            }
        }
        else
        {
            if (value == null || UpperBound == null)
            {
                UpperBound = null;
            }
            else if (CompareValue(value, UpperBound, ValueType) > 0)
            {
                UpperBound = value;
            }
        }
    }


    /// <summary>
    ///     检查区间的重合情况。
    /// </summary>
    /// <param name="lowerBound">检查的区间下限</param>
    /// <param name="upperBound">检查的区间上限</param>
    /// <returns></returns>
    /// <remarks>需要保证upperBound >= lowerBound</remarks>
    public MetadataRangeOverlapType CheckOverlap(object? lowerBound, object? upperBound)
    {
        if (lowerBound == LowerBound && upperBound == UpperBound)
        {
            return MetadataRangeOverlapType.Equal;
        }

        // [..] 是全集，覆盖所有区间
        if (lowerBound == null && upperBound == null)
        {
            return MetadataRangeOverlapType.Cover;
        }

        int left = int.MaxValue; // lowerBound 和 LowerBound 的比较结果
        int right = int.MaxValue; // upperBound 和 UpperBound 的比较结果
        int leftRight = int.MaxValue; // lowerBound 和 UpperBound 的比较结果
        int rightLeft = int.MaxValue; // upperBound 和 LowerBound 的比较结果

        if (lowerBound != null)
        {
            left = LowerBound != null ? CompareValue(lowerBound, LowerBound, ValueType) : 1;

            if (UpperBound != null)
            {
                leftRight = CompareValue(lowerBound, UpperBound, ValueType);
            }
        }

        if (upperBound != null)
        {
            if (UpperBound != null)
            {
                right = CompareValue(upperBound, UpperBound, ValueType);
            }
            else
            {
                right = -1;
            }

            if (LowerBound != null)
            {
                rightLeft = CompareValue(upperBound, LowerBound, ValueType);
            }
        }

        if (leftRight != int.MaxValue && leftRight > 0)
        {
            return MetadataRangeOverlapType.LeftNoIntersection;
        }

        if (rightLeft != int.MaxValue && rightLeft < 0)
        {
            return MetadataRangeOverlapType.RightNoIntersection;
        }

        if (left == 0 && right == 0)
        {
            return MetadataRangeOverlapType.Equal;
        }

        if (leftRight == 0)
        {
            return MetadataRangeOverlapType.LeftNeighbourhood;
        }

        if (rightLeft == 0)
        {
            return MetadataRangeOverlapType.RightNeighbourhood;
        }

        if (left != int.MaxValue && left >= 0 && right <= 0)
        {
            return MetadataRangeOverlapType.Include;
        }

        if (left <= 0 && right != int.MaxValue && right >= 0)
        {
            return MetadataRangeOverlapType.Cover;
        }

        if (left < 0)
        {
            return MetadataRangeOverlapType.LeftIntersection;
        }

        return MetadataRangeOverlapType.RightIntersection;
    }


    /// <summary>
    ///     比较给定值范围和当前区间的重合关系。
    /// </summary>
    /// <param name="range">给定区间</param>
    /// <returns></returns>
    public MetadataRangeOverlapType CheckOverlap(MetadataValueRange range)
    {
        return CheckOverlap(range.LowerBound, range.UpperBound);
    }


    /// <summary>
    ///     检查给定区间对象和当前对象是否相连并将其合并进当前范围。
    /// </summary>
    /// <param name="range">需要合并的区间</param>
    /// <returns>如果合并成功，返回true，否则，返回false</returns>
    /// <remarks>
    ///     在合并前，会检查<paramref name="range" />区间的上下限是否和当前区间相连（包括有交集和没有交集）
    /// </remarks>
    public bool Merge(MetadataValueRange range)
    {
        MetadataRangeOverlapType overlap = CheckOverlap(range.LowerBound, range.UpperBound);

        if (overlap == MetadataRangeOverlapType.LeftNoIntersection ||
            overlap == MetadataRangeOverlapType.RightNoIntersection)
        {
            return false;
        }

        if (overlap == MetadataRangeOverlapType.LeftIntersection)
        {
            LowerBound = range.LowerBound;
            return true;
        }

        if (overlap == MetadataRangeOverlapType.RightIntersection)
        {
            UpperBound = range.UpperBound;
            return true;
        }

        return false;
    }
}

/// <summary>
///     字段值区间集合
/// </summary>
public interface IMetadataValueRanges : IEnumerable<MetadataValueRange>
{
    /// <summary>
    ///     区间对象所在的字段。
    /// </summary>
    IField OwnerField { get; }

    /// <summary>
    ///     子区间个数
    /// </summary>
    int Count { get; }

    /// <summary>
    ///     总体的下限
    /// </summary>
    object? LowerBound { get; }

    /// <summary>
    ///     总体的下限
    /// </summary>
    object? UpperBound { get; }

    /// <summary>
    ///     区间中的值类型，可以是字符串、日期、整数、小数。
    /// </summary>
    MetadataRangeValueType ValueType { get; }

    /// <summary>
    ///     区间表达式
    /// </summary>
    string RangeExpression { get; }

    /// <summary>
    ///     获取指定索引的区间对象
    /// </summary>
    /// <param name="index">指定索引</param>
    /// <returns>区间对象</returns>
    MetadataValueRange this[int index] { get; }

    /// <summary>
    ///     尝试查找指定上下限的已有区间。
    /// </summary>
    /// <param name="upperBound">指定上限</param>
    /// <param name="lowerBound">指定下限</param>
    /// <param name="range">查找到的区间，如果未找到，此值是null</param>
    /// <param name="overlapType">查找到的区间和给定上下限的交叉关系</param>
    /// <returns>如果成功查找到，返回true，否则，返回false</returns>
    /// <remarks>
    ///     会返回满足下面的交叉关系的区间：
    ///     <list type="number">
    ///         <item>
    ///             <see cref="MetadataRangeOverlapType.Equal" />
    ///         </item>
    ///         <item>
    ///             <see cref="MetadataRangeOverlapType.Cover" />
    ///         </item>
    ///         <item>
    ///             <see cref="MetadataRangeOverlapType.Include" />
    ///         </item>
    ///         <item>
    ///             <see cref="MetadataRangeOverlapType.LeftIntersection" />
    ///         </item>
    ///         <item>
    ///             <see cref="MetadataRangeOverlapType.RightIntersection" />
    ///         </item>
    ///         <item>
    ///             <see cref="MetadataRangeOverlapType.LeftNeighbourhood" />
    ///         </item>
    ///         <item>
    ///             <see cref="MetadataRangeOverlapType.RightNeighbourhood" />
    ///         </item>
    ///     </list>
    /// </remarks>
    bool TryFind(object lowerBound, object upperBound,
        [NotNullWhen(true)] out MetadataValueRange? range,
        out MetadataRangeOverlapType overlapType);

    /// <summary>
    ///     获取包含给定值的子区间索引。
    /// </summary>
    /// <param name="value">给定区间值</param>
    /// <returns>子区间的索引</returns>
    /// <remarks>
    ///     优先返回包含此值的区间，如果没有包含此值的区间索引，返回第一个大于此值的区间索引。
    /// </remarks>
    int IndexOf(object value);

    /// <summary>
    ///     查找包含给定值的子区间。
    /// </summary>
    /// <param name="value">给定区间值</param>
    /// <returns>包含给定值的子区间</returns>
    /// <remarks>
    ///     优先返回包含此值的区间，如果没有包含此值的区间，返回第一个大于此值的区间。
    /// </remarks>
    MetadataValueRange? Find(object value);

    /// <summary>
    ///     向区间集合中添加新的子区间。
    /// </summary>
    /// <param name="upperBound">子区间下限</param>
    /// <param name="lowerBound">子区间上限</param>
    /// <param name="step">区间的间隔值</param>
    void Add(object? upperBound, object? lowerBound, object? step = null);

    /// <summary>
    ///     添加区间表达式。
    /// </summary>
    /// <param name="expression">区间表达式，格式是 [[lower] .. [upper]]</param>
    void AddExpression(string expression);

    /// <summary>
    ///     移除指定位置的区间对象。
    /// </summary>
    /// <param name="index"></param>
    void RemoveAt(int index);
}

/// <summary>
///     MDM文档中分类列表定义对象。
/// </summary>
public interface IMetadataType : IMetadataLabeledObject
{
    /// <summary>
    ///     分类字段是否使用全局命名空间。如果此属性是true，分类字段中元素全名将和名称相同，否则，将带有此对象名称前缀。
    /// </summary>
    bool Namespace { get; }

    /// <summary>
    ///     分类类别定义列表。
    /// </summary>
    IElements Elements { get; }
}

/// <summary>
///     MDM文档中分类定义集合。
/// </summary>
public interface IMetadataTypes<T> : IMetadataLabeledCollection<T> where T : class, IMetadataType
{
    /// <summary>
    ///     字段是否使用全局命名空间。如果此属性是true，分类字段中元素全名将和名称相同，否则，将带有此对象名称前缀。
    /// </summary>
    bool Namespace { get; set; }
}

/// <summary>
///     通过define定义的分类列表。
/// </summary>
public interface IElementList : IMetadataType
{
    /// <summary>
    ///     分类列表的级别深度。
    /// </summary>
    int LevelDepth { get; }

    /// <summary>
    ///     分类列表的值。
    /// </summary>
    int Value { get; }

    /// <summary>
    ///     引用的分类列表UUID。
    /// </summary>
    string ReferenceId { get; set; }

    /// <summary>
    ///     引用的分类列表对象。
    /// </summary>
    IElementList? Reference { get; }

    /// <summary>
    ///     获取当前有效的分类列表，优先使用引用列表。
    /// </summary>
    /// <returns></returns>
    IElements GetElements();
}


/// <summary>
///     元数据文档中的分类元素列表定义集合。
/// </summary>
public interface IMetadataTypes : IMetadataTypes<IElementList>
{
}

/// <summary>
///     字段信息类型。
/// </summary>
public enum FieldInfoTypes
{
    None,
    Values,
    Missings,
    Flags,
    Other
}

/// <summary>
///     此接口表示MDMDocument中的元数据字段定义，类型对应<see cref="FieldDataType" />中的定义
/// </summary>
public interface IField : IMetadataType
{
    /// <summary>
    ///     字段的级别深度。
    /// </summary>
    int LevelDepth { get; }

    /// <summary>
    ///     此字段的数据类型。
    /// </summary>
    FieldDataType DataType { get; }

    /// <summary>
    ///     字段信息类型。
    /// </summary>
    FieldInfoTypes FieldInfo { get; }

    /// <summary>
    ///     引用的变量定义UUID。
    /// </summary>
    string? ReferenceId { get; }

    /// <summary>
    ///     当前字段引用的其他字段，如果不引用，此属性是null。
    /// </summary>
    IField? Reference { get; }

    /// <summary>
    ///     字段区间定义
    /// </summary>
    IMetadataValueRanges Ranges { get; }

    /// <summary>
    ///     当前字段中类型是<see cref="ElementType.Category" />的IElement类型元素列表。
    /// </summary>
    ICategories Categories { get; }

    /// <summary>
    ///     当前变量是否是系统变量。
    /// </summary>
    bool IsSystem { get; }
}

/// <summary>
///     当前元数据的文档字段集合，只允许通过元数据对象内部创建。
/// </summary>
public interface IFields : IMetadataTypes<IField>
{
    /// <summary>
    ///     创建一个循环字段。
    /// </summary>
    /// <param name="name">字段名</param>
    /// <param name="id">字段ID</param>
    IArray CreateArray(string name, string id = "");

    /// <summary>
    ///     创建一个变量引用字段。
    /// </summary>
    /// <param name="name">变量名</param>
    /// <param name="referenceId">引用的变量UUID</param>
    /// <param name="fullName">指定的变量全名</param>
    /// <param name="id">指定的变量ID</param>
    IVariable CreateVariableReference(string name, string referenceId, string? fullName = null, string id = "");

    /// <summary>
    ///     创建一个横向和纵向使用相同分类列表的字段。
    /// </summary>
    /// <param name="name">字段名</param>
    /// <param name="id">字段ID</param>
    ICompound CreateCompound(string name, string id = "");
}


/// <summary>
///     当前字段的
/// </summary>
public interface IHelperFields : IMetadataNamedObject, IMetadataStringKeyCollection<IVariable>
{
    /// <summary>
    ///     分类字段是否使用全局命名空间。如果此属性是true，分类字段中元素全名将和名称相同，否则，将带有此对象名称前缀。
    /// </summary>
    bool Namespace { get; set; }
}


/// <summary>
///     标记变量的用途。
/// </summary>
[Flags]
public enum VariableUsage
{
    Variable = 0,
    Grid = 1 << 0,
    Compound = 1 << 1,
    Class = 1 << 2,
    Array = 1 << 3,
    HelperField = 1 << 4,
    SourceFile = 1 << 8 | HelperField,
    Coding = 1 << 9 | HelperField,
    OtherSpecify = 1 << 10 | HelperField,
    Multiplier = 1 << 11 | HelperField,
    Filter = 1 << 12,
    Weight = 1 << 13
}

/// <summary>
///     存储MDM文档内的字段变量定义。
/// </summary>
public interface IVariable : IField
{
    /// <summary>
    ///     数据库变量属性。
    /// </summary>
    IProperties DataSourceProperties { get; }

    /// <summary>
    ///     提示当前变量是否不保存具体数据。
    /// </summary>
    bool NoCaseData { get; }

    /// <summary>
    ///     描述变量用途，使用二进制Flag
    /// </summary>
    VariableUsage UsageType { get; }

    /// <summary>
    ///     帮助字段名集合。
    /// </summary>
    IHelperFields HelperFields { get; }

    /// <summary>
    ///     编码使用的变量，标识脚本中 codes() 定义的部分。
    /// </summary>
    IVariable? Codes { get; }

    /// <summary>
    ///     其他分类定义。
    /// </summary>
    ICategories? OtherCategories { get; }

    /// <summary>
    ///     变量值的最小值。
    /// </summary>
    object? MinValue { get; }

    /// <summary>
    ///     变量值的最大值。
    /// </summary>
    object? MaxValue { get; }

    /// <summary>
    ///     变量值的有效最小值。
    /// </summary>
    object? EffectiveMinValue { get; }

    /// <summary>
    ///     变量值的有效最大值。
    /// </summary>
    object? EffectiveMaxValue { get; }

    /// <summary>
    ///     初始值
    /// </summary>
    object? InitialAnswer { get; }

    /// <summary>
    ///     默认值
    /// </summary>
    object? DefaultAnswer { get; }

    /// <summary>
    ///     数值精确位数
    /// </summary>
    int? Precision { get; }

    /// <summary>
    ///     变量末尾的表达式，使用expression()定义。
    /// </summary>
    string? Expression { get; }

    /// <summary>
    ///     变量的轴表达式
    /// </summary>
    string? AxisExpression { get; }

    /// <summary>
    ///     当前字段是否是数据库字段。
    /// </summary>
    bool IsDbQuestion { get; }

    /// <summary>
    ///     数据库变量属性类型。
    /// </summary>
    DbQuestionTypes DbQuestionType { get; }

    /// <summary>
    ///     数据库变量数据类型。
    /// </summary>
    FieldDataType DbDataType { get; }

    /// <summary>
    ///     数据库变量元素列表。
    /// </summary>
    IDbElements? DbElements { get; }

    /// <summary>
    ///     IArray类型变量的排列方向。
    /// </summary>
    Orientations Orientation { get; set; }

    /// <summary>
    ///     字段值的有效性检查字符串。
    /// </summary>
    string? Validation { get; set; }

    /// <summary>
    ///     字段答案大小限制。
    /// </summary>
    int? Scale { get; set; }

    /// <summary>
    ///     当对象分类元素是否自动填充，当变量位于<see cref="ICompound" />类型变量的下级变量时，
    ///     此值是true，此时，将使用和父级变量相同的分类列表。
    /// </summary>
    bool AutoElements { get; }
}


/// <summary>
///     一个循环层和循环下层分类列表相同的变量定义。
/// </summary>
public interface ICompound : IField
{
    /// <summary>
    ///     分类元素列表定义集合。
    /// </summary>
    IMetadataTypes Types { get; }

    /// <summary>
    ///     下级字段集合。
    /// </summary>
    IFields Fields { get; }

    /// <summary>
    ///     页面定义变量集合。
    /// </summary>
    IPages Pages { get; }

    /// <summary>
    ///     路由配置集合，此集合的<see cref="INamedObject.Name" />属性不应该是空。
    /// </summary>
    IRoutings Routings { get; }


    /// <summary>
    ///     ICompound类型下级变量的排列方向。
    /// </summary>
    Orientations Orientation { get; set; }

    /// <summary>
    ///     创建一个普通的次级变量。
    /// </summary>
    /// <param name="name">变量名</param>
    /// <param name="dataType">变量数据类型</param>
    IVariable CreateVariable(string name, FieldDataType dataType);

    /// <summary>
    ///     创建一个循环的次级变量。此变量的循环类型固定是<see cref="IteratorTypes.Categorical" />。
    /// </summary>
    /// <param name="name">变量名</param>
    IArray CreateArray(string name);
}


/// <summary>
///     XML文档中 page Tag下 item Tag 元素的内容。
/// </summary>
public interface IPageItem : IMetadataNamedObject
{
    /// <summary>
    ///     页面配置元素的Id编号。
    /// </summary>
    string Id { get; }

    /// <summary>
    ///     页面元素引用的变量定义。
    /// </summary>
    IVariable? Reference { get; }

    /// <summary>
    ///     引用的变量ID。
    /// </summary>
    string ReferenceId { get; set; }
}


/// <summary>
///     XML文档中page Tag定义的元素。
/// </summary>
public interface IPage : IMetadataLabeledCollection<IPageItem>
{
    /// <summary>
    ///     是否使用全局命名空间。
    /// </summary>
    bool Namespace { get; }

    /// <summary>
    ///     页面元素引用的页面定义。
    /// </summary>
    IPage? Reference { get; }

    /// <summary>
    ///     引用的变量ID。
    /// </summary>
    string ReferenceId { get; set; }
}

/// <summary>
///     XML文档中pages Tag定义的元素。
/// </summary>
public interface IPages : IMetadataLabeledCollection<IPage>
{
    /// <summary>
    ///     是否使用全局命名空间。
    /// </summary>
    bool Namespace { get; }
}

/// <summary>
///     迭代器类型
/// </summary>
public enum IteratorTypes
{
    Number = 1,
    Categorical,
    NumericRanges
}

/// <summary>
///     循环字段类型
/// </summary>
public enum ArrayTypes
{
    Level,
    Expand
}

/// <summary>
///     描述循环字段
/// </summary>
public interface IArray : IField
{
    /// <summary>
    ///     上层循环类型
    /// </summary>
    IteratorTypes IteratorType { get; }

    /// <summary>
    ///     下层循环类型
    /// </summary>
    ArrayTypes ArrayType { get; }

    /// <summary>
    ///     循环下级变量的排列方向
    /// </summary>
    Orientations Orientation { get; }

    /// <summary>
    ///     下级变量定义
    /// </summary>
    IMetadataClass Class { get; }

    /// <summary>
    ///     当前字段是否是数据库字段。
    /// </summary>
    bool IsDbQuestion { get; }

    /// <summary>
    ///     数据库变量属性类型。
    /// </summary>
    DbQuestionTypes DbQuestionType { get; }

    /// <summary>
    ///     数据库变量数据类型。
    /// </summary>
    FieldDataType DbDataType { get; }

    /// <summary>
    ///     数据库变量元素列表。
    /// </summary>
    IDbElements DbElements { get; }

    /// <summary>
    ///     是否是Grid。
    /// </summary>
    bool IsGrid { get; }

    /// <summary>
    ///     是否衍生元素。
    /// </summary>
    bool DeriveElements { get; }

    /// <summary>
    ///     轴表达式
    /// </summary>
    string? AxisExpression { get; }

    /// <summary>
    ///     默认值
    /// </summary>
    object? DefaultAnswer { get; }


    /// <summary>
    ///     初始值
    /// </summary>
    object? InitialAnswer { get; }

    /// <summary>
    ///     帮助字段名集合。
    /// </summary>
    IHelperFields HelperFields { get; }


    /// <summary>
    ///     当对象分类元素是否自动填充，当变量位于<see cref="ICompound" />类型变量的下级变量时，
    ///     此值是true，此时，将使用和父级变量相同的分类列表。
    /// </summary>
    bool AutoElements { get; set; }

    /// <summary>
    ///     添加一个新的下级分类列表。
    /// </summary>
    /// <param name="name">分类列表名</param>
    /// <returns>新创建的分类列表</returns>
    IElementList CreateElementList(string name);

    /// <summary>
    ///     创建一个新的次级普通变量。
    /// </summary>
    /// <param name="name">变量名</param>
    /// <param name="dataType">变量数据类型</param>
    /// <returns>新创建变量对象</returns>
    IVariable CreateVariable(string name, FieldDataType dataType);

    /// <summary>
    ///     创建一个新的次级循环变量。
    /// </summary>
    /// <param name="name">变量名</param>
    /// <param name="iteratorType">变量循环类型</param>
    /// <returns>新创建的循环变量</returns>
    IArray CreateArray(string name, IteratorTypes iteratorType);

    /// <summary>
    ///     创建一个新的次级块变量。
    /// </summary>
    /// <param name="name">变量名</param>
    /// <returns>新创建的块变量</returns>
    IBlock CreateBlock(string name);
}


/// <summary>
///     块状字段定义，此字段下存储子字段，可以起到类似命名空间的作用。
/// </summary>
public interface IBlock : IField
{
    /// <summary>
    ///     分类元素列表定义集合。
    /// </summary>
    IMetadataTypes Types { get; }

    /// <summary>
    ///     下级字段定义集合
    /// </summary>
    IFields Fields { get; }

    /// <summary>
    ///     上下文路由信息。
    /// </summary>
    IRoutings Routings { get; }

    /// <summary>
    ///     页面定义集合。
    /// </summary>
    IPages Pages { get; }

    /// <summary>
    ///     添加一个新的下级分类列表。
    /// </summary>
    /// <param name="name">分类列表名</param>
    /// <returns>新创建的分类列表</returns>
    IElementList CreateElementList(string name);

    /// <summary>
    ///     创建一个次级普通变量。
    /// </summary>
    /// <param name="name">变量名</param>
    /// <param name="dataType">变量数据类型</param>
    /// <returns>新创建的变量对象</returns>
    IVariable CreateVariable(string name, FieldDataType dataType);

    /// <summary>
    ///     创建一个新的次级循环变量。
    /// </summary>
    /// <param name="name">变量名</param>
    /// <param name="iteratorType">变量循环类型</param>
    /// <returns>新创建的循环变量</returns>
    IArray CreateArray(string name, IteratorTypes iteratorType);

    /// <summary>
    ///     创建一个新的次级块变量。
    /// </summary>
    /// <param name="name">变量名</param>
    /// <returns>新创建的块变量</returns>
    IBlock CreateBlock(string name);

    /// <summary>
    ///     创建一个新的页面定义变量。
    /// </summary>
    /// <param name="name">变量名</param>
    /// <returns>新创建的页面变量</returns>
    IPage CreatePage(string name);
}


/// <summary>
///     数据库变量类型
/// </summary>
public enum DbQuestionTypes
{
    /// <summary>
    ///     未知类型，默认值，提示变量不是数据库变量
    /// </summary>
    Unknown,

    /// <summary>
    ///     单值变量
    /// </summary>
    SingleResponse,

    /// <summary>
    ///     多值变量
    /// </summary>
    MultipleResponse,

    /// <summary>
    ///     循环变量
    /// </summary>
    Array
}


/// <summary>
///     排序类型。
/// </summary>
public enum OrderTypes
{
    /// <summary>
    ///     默认排序类型。
    /// </summary>
    Normal,

    /// <summary>
    ///     随机。
    /// </summary>
    Randomize,

    /// <summary>
    ///     旋转。
    /// </summary>
    Rotate,

    /// <summary>
    ///     反转。
    /// </summary>
    Reverse,

    /// <summary>
    ///     升序。
    /// </summary>
    Ascending,

    /// <summary>
    ///     降序。
    /// </summary>
    Descending,

    /// <summary>
    ///     自定义。
    /// </summary>
    Custom
}


public class DbColumnMapItems
{
    /// <summary>
    ///     唯一编号
    /// </summary>
    public string Id { get; set; } = string.Empty;

    /// <summary>
    ///     标签
    /// </summary>
    public string Label { get; set; } = string.Empty;

    /// <summary>
    ///     键盘映射名
    /// </summary>
    public string KeyCode { get; set; } = string.Empty;


    /// <summary>
    ///     文件名
    /// </summary>
    public string File { get; set; } = string.Empty;


    /// <summary>
    ///     列分析值
    /// </summary>
    public string? AnalysisValue { get; set; } = null;


    /// <summary>
    ///     固定值
    /// </summary>
    public string? Fixed { get; set; } = null;


    /// <summary>
    ///     排除值
    /// </summary>
    public string? Exclusive { get; set; } = null;
}


/// <summary>
///     数据库题目配置属性。
/// </summary>
public class DbQuestionOptions(IMetadataObject parent)
{
    /// <summary>
    ///     数据库题目配置所在的变量。
    /// </summary>
    public IMetadataObject Parent { get; private set; } = parent;

    /// <summary>
    ///     数据库链接字符串
    /// </summary>
    public string ConnectionString { get; set; } = string.Empty;


    /// <summary>
    ///     数据库表名
    /// </summary>
    public string Table { get; set; } = string.Empty;


    /// <summary>
    ///     数据库列元素配置
    /// </summary>
    public DbColumnMapItems? Columns { get; set; } = null;


    /// <summary>
    ///     答案的最小值
    /// </summary>
    public object? MinAnswers { get; set; } = null;


    /// <summary>
    ///     答案的最大值
    /// </summary>
    public object? MaxAnswers { get; set; } = null;


    /// <summary>
    ///     数据库筛选条件
    /// </summary>
    public string? SqlFilter { get; set; } = null;


    /// <summary>
    ///     Cache的过期时间
    /// </summary>
    public int? CacheTimeout { get; set; } = null;


    /// <summary>
    ///     列排序类型
    /// </summary>
    public OrderTypes Order { get; set; } = OrderTypes.Normal;


    /// <summary>
    ///     迭代器的数据类型
    /// </summary>
    public FieldDataType? IteratorIdType { get; set; } = null;


    /// <summary>
    ///     是否链接Cache
    /// </summary>
    public bool? CacheConnection { get; set; } = null;


    /// <summary>
    ///     修改当前配置所属的父对象。
    /// </summary>
    /// <param name="parent">父对象</param>
    public void SetParent(IMetadataObject parent)
    {
        Parent = parent;
    }
}


/// <summary>
///     数据库变量元素列表。
/// </summary>
public interface IDbElements : IElements
{
    /// <summary>
    ///     数据库变量配置属性。
    /// </summary>
    DbQuestionOptions DbQuestionOptions { get; }
}


/// <summary>
///     数据源类型
/// </summary>
public enum SourceTypes
{
    DataField = 1,
    Expression = 2,
    Expressions = 4,
    NoCaseData = 8,
    None = 0x1000
}


/// <summary>
///     MDM变量实例列表。
/// </summary>
public interface IVariables : IMetadataTypes<IVariable>
{
}


/// <summary>
///     存储元数据文档的变量实例定义
/// </summary>
public interface IVariableInstance : IMetadataNamedObject
{
    /// <summary>
    ///     变量的数据源类型
    /// </summary>
    SourceTypes SourceType { get; set; }

    /// <summary>
    ///     引用的变量ID。
    /// </summary>
    string VariableId { get; set; }

    /// <summary>
    ///     获取引用的变量对象。
    /// </summary>
    IVariable? Variable { get; }

    /// <summary>
    ///     变量实例的实例分类元素列表。
    /// </summary>
    IElementInstances Elements { get; }
}


/// <summary>
///     存储数据文档变量实例的列表
/// </summary>
public interface IVariableInstances : IMetadataObjectCollection
{
    /// <summary>
    ///     当前元数据对象所属的元数据文档。
    /// </summary>
    IMetadataDocument Document { get; }

    /// <summary>
    ///     创建一个新的变量实例。
    /// </summary>
    /// <param name="name">实例名</param>
    /// <param name="referenceId">引用变量ID</param>
    /// <param name="fullName">实例全名</param>
    /// <returns></returns>
    IVariableInstance CreateObject(string name, string referenceId, string? fullName = null);
}